#pragma once
#include "HashTable.h"

namespace ape
{
	template <class K, class V, class Hash = HashFunc<K>>
	class unordered_map
	{
	public:
		// 获得key
		struct MapGetKey
		{
			const K &operator()(const pair<K, V> &pair)
			{
				return pair.first;
			}
		};

	private:
	public:
		ChainAddressing::HashTable<K, pair<const K, V>, MapGetKey, Hash> _ht;

	public:
		typedef typename ChainAddressing::HashTable<K, pair<const K, V>, MapGetKey, Hash>::iterator iterator;
		typedef typename ChainAddressing::HashTable<K, pair<const K, V>, MapGetKey, Hash>::const_iterator const_iterator;

		// 迭代器
		iterator begin()
		{
			return _ht.begin();
		}

		iterator end()
		{
			return _ht.end();
		}

		const_iterator begin() const
		{
			return _ht.begin();
		}

		const_iterator end() const
		{
			return _ht.end();
		}

		// 插入
		pair<iterator, bool> insert(const pair<K, V> &pair)
		{
			return _ht.Insert(pair);
		}

		// 下标运算符
		V &operator[](const K &key)
		{
			pair<iterator, bool> pair = insert(make_pair(key, V()));
			return pair.first->second;
		}

		// 查找
		iterator find(const K &key)
		{
			return _ht.Find(key);
		}

		// 删除
		bool erase(const K &key)
		{
			return _ht.Erase(key);
		}
	};

	void test_unordered_map1()
	{
		unordered_map<int, int> m;
		m.insert(make_pair(1, 1));
		m.insert(make_pair(3, 3));
		m.insert(make_pair(2, 2));

		unordered_map<int, int>::iterator it = m.begin();
		while (it != m.end())
		{
			cout << it->first << ":" << it->second << endl;
			++it;
		}
		cout << endl;
	}

	void test_unordered_map2()
	{
		string s[] = {"西瓜", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉", "梨"};
		unordered_map<string, int> um;
		for (auto &e : s)
		{
			um[e]++;
		}

		for (auto &pair : um)
		{
			cout << pair.first << ":" << pair.second << endl;
		}
	}

	class Date
	{
		friend struct HashDate;
		friend ostream &operator<<(ostream &_cout, const Date &d);

	public:
		Date(int year = 1900, int month = 1, int day = 1)
			: _year(year), _month(month), _day(day)
		{
		}

		bool operator<(const Date &d) const
		{
			return (_year < d._year) || (_year == d._year && _month < d._month) || (_year == d._year && _month == d._month && _day < d._day);
		}

		bool operator>(const Date &d) const
		{
			return (_year > d._year) || (_year == d._year && _month > d._month) || (_year == d._year && _month == d._month && _day > d._day);
		}

		bool operator==(const Date &d) const
		{
			return _year == d._year && _month == d._month && _day == d._day;
		}

	private:
		int _year;
		int _month;
		int _day;
	};
	ostream &operator<<(ostream &_cout, const Date &d)
	{
		_cout << d._year << "-" << d._month << "-" << d._day;
		return _cout;
	}

	struct HashDate
	{
		size_t operator()(const Date &d)
		{
			size_t value = 0;

			value += d._year;
			value *= 131;

			value += d._month;
			value *= 131;

			value += d._day;
			value *= 131;

			return value;
		}
	};

	void test_unordered_map4()
	{
		Date d1(2023, 10, 1);
		Date d2(2023, 10, 5);
		Date d3(2023, 10, 2);
		Date d4(2023, 10, 2);
		Date d5(2023, 10, 2);
		Date d6(2023, 10, 1);

		Date a[] = {d1, d2, d3, d4, d5, d6};

		unordered_map<Date, int, HashDate> um;
		for (auto e : a)
		{
			um[e]++;
		}

		for (auto &pair : um)
		{
			cout << pair.first << ":" << pair.second << endl;
		}
	}

	// 测试unordered_map性能 哈希桶最大个数
	void test_unordered_map5()
	{
		unordered_map<int, int> m;
		// 插入100万随机数
		srand(time(NULL));
		for (int i = 0; i < 1000000; ++i)
		{
			m.insert(make_pair(rand(), rand()));
		}

		size_t max =  m._ht.MaxBucketSize();
		cout << max << endl;
	}
}
